package com.cougil.uoc.seghismed.model;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CollectionOfElements;
import org.hibernate.annotations.MapKeyManyToMany;

import com.cougil.uoc.seghismed.model.ciphed.MetgeCiphed;
import com.cougil.uoc.seghismed.model.ciphed.VisitaCiphed;

/**
 * Entitat de negoci que representa pròpiament l'Historial d'un Pacient
 * @author Ignacio Cougil Jares
 *
 */

@Entity
@Table(name="HISTORIAL")
/*
@AttributeOverrides({
    @AttributeOverride( name="metgesAmbAccesProtegit.element", column = @Column(name="DataLimit") ),
    @AttributeOverride( name="metgesAmbAccesProtegit.key", column = @Column(name="IdMetgeCiphed") )
})
*/
public class Historial {

	@Id
	@GeneratedValue
	private Integer id;

	@CollectionOfElements(fetch=FetchType.EAGER, targetElement = java.util.Date.class)
	@MapKeyManyToMany(
		targetEntity = MetgeCiphed.class,
		joinColumns={@JoinColumn(name="IDMETGECIPHED", table="HISTORIAL_METGECIPHED")}
	)
	@JoinTable(
    	name="HISTORIAL_METGECIPHED",
   		joinColumns={@JoinColumn(name="IDHISTORIAL")}
    )
	@Column(name = "DATALIMIT", nullable = true)
	// llista de metges amb permís per accedir a l'historial i fins quan
	private Map<MetgeCiphed, Date> metgesAmbAccesProtegit = new HashMap<MetgeCiphed, Date>();

	@OneToOne(fetch=FetchType.EAGER)
	@JoinColumn(name="IDPACIENT",referencedColumnName="ID")
	// pacient del qual és l'historial
    private Pacient pacient;

	@OneToMany(fetch = FetchType.EAGER)
	@Cascade(value = { org.hibernate.annotations.CascadeType.DELETE_ORPHAN,
			org.hibernate.annotations.CascadeType.SAVE_UPDATE })
    @JoinTable(
    	name="HISTORIAL_VISITACIPHED",
        joinColumns={@JoinColumn(name="IDHISTORIAL")},
        inverseJoinColumns={@JoinColumn(name="IDVISITACIPHED")}
    )
    // llista de visites xifrada
	private Set<VisitaCiphed> visitesProtegides = new HashSet<VisitaCiphed>();

	/**
	 * Afegeix un nou metge més la informació de fins quan tindrà accés a l'historial
	 * @param metge {@link MetgeCiphed} metge a afegir
	 * @param dataLimit {@link Date} data fins la qual tindrà accés el metge
	 * @return {@link Date} anterior data associada al metge o null en cas contrari
	 * @see java.util.Map#put(java.lang.Object, java.lang.Object)
	 */
	public Date addMetge(MetgeCiphed metge, Date dataLimit) {
		return this.metgesAmbAccesProtegit.put(metge, dataLimit);
	}

	/**
	 * Afegeix una visita xifrada nova a la llista
	 *
	 * @param visita
	 *            xifrada {@link VisitaCiphed} a afegir
	 * @return true si la llista no contenia previament la llista a afegir
	 * @see java.util.Set#add(java.lang.Object)
	 */
	public boolean addVisita(VisitaCiphed e) {
		return this.visitesProtegides.add(e);
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(final Object other) {
		if (!(other instanceof Historial)) {
			return false;
		}
		Historial castOther = (Historial) other;
		return new EqualsBuilder().append(this.id, castOther.id).isEquals();
	}

	/**
	 * Retorna una col·leció amb el conjunt de dates disponibles associades als metges
	 * @return {@link Collection<Date>} iterador amb el conjunt d'elements
	 * @see java.util.Map#values()
	 */
	public Collection<Date> getDatesMetges() {
		return this.metgesAmbAccesProtegit.values();
	}

	/**
	 * @return Retorna el valor de la propietat id
	 */
	public Integer getId() {
		return this.id;
	}

	/**
	 * Retorna una col·leció amb el conjunt de metges disponibles associats a l'historial
	 * @return {@link Set<MetgeCiphed>} set amb el conjunt d'elements
	 * @see java.util.Map#keySet()
	 */
	public Set<MetgeCiphed> getMetges() {
		return this.metgesAmbAccesProtegit.keySet();
	}

	/**
	 * @return Retorna el valor de la propietat metgesAmbAccesProtegit
	 */
	public Map<MetgeCiphed, Date> getMetgesAmbAccesProtegit() {
		return this.metgesAmbAccesProtegit;
	}

	/**
	 * @return Retorna el valor de la propietat pacient
	 */
	public Pacient getPacient() {
		return this.pacient;
	}

	/**
	 * @return Retorna el valor de la propietat visitesProtegides
	 */
	public Set<VisitaCiphed> getVisitesProtegides() {
		return this.visitesProtegides;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return new HashCodeBuilder().append(this.id).toHashCode();
	}


	/**
	 * Retorna un iterador amb el conjunt de metges xifrades associats
	 * @return {@link Iterator} iterador amb el conjunt d'elements
	 * @see java.util.Set#iterator()
	 */
	public Iterator<MetgeCiphed> iteratorMetges() {
		return this.metgesAmbAccesProtegit.keySet().iterator();
	}

	/**
	 * Retorna un iterador amb el conjunt de visites xifrades associades
	 * @return {@link Iterator} iterador amb el conjunt d'elements
	 * @see java.util.Set#iterator()
	 */
	public Iterator<VisitaCiphed> iteratorVisites() {
		return this.visitesProtegides.iterator();
	}

	/**
	 * Elimina un metge de la llista de metges amb accés a l'historial
	 * @param metge {@link MetgeCiphed} xifrat que es preten eliminar
	 * @return la data {@link Date} associada al metge informat
	 * @see java.util.Map#remove(java.lang.Object)
	 */
	public Date removeMetge(MetgeCiphed metge) {
		return this.metgesAmbAccesProtegit.remove(metge);
	}

	/**
	 * Elimina una visita de la llista de visites de l'historial
	 *
	 * @param visita
	 *            {@link VisitaCiphed} xifrada que es preten eliminar
	 * @return true si la visita s'ha elminat del conjunt
	 * @see java.util.Set#remove(java.lang.Object)
	 */
	public boolean removeVisita(VisitaCiphed visita) {
		return this.visitesProtegides.remove(visita);
	}

	/**
	 * @param Estableix id com a valor de la propietat id
	 */
	public void setId(Integer id) {
		this.id = id;
	}


	/**
	 * @param Estableix
	 *            metgesAmbAccesProtegit com a valor de la propietat metgesAmbAccesProtegit
	 */
	public void setMetgesAmbAccesProtegit(Map<MetgeCiphed, Date> metgesAmbAccesProtegit) {
		this.metgesAmbAccesProtegit = metgesAmbAccesProtegit;
	}

	/**
	 * @param pacient Estableix el valor de la propietat pacient
	 */
	public void setPacient(Pacient pacient) {
		this.pacient = pacient;
	}

	/**
	 * @param Estableix visitesProtegides com a valor de la propietat visitesProtegides
	 */
	public void setVisitesProtegides(Set<VisitaCiphed> visitesProtegides) {
		this.visitesProtegides = visitesProtegides;
	}

	/**
	 * Retorna el nombre de metges associats
	 * @return nombre d'elements
	 * @see java.util.Map#size()
	 */
	public int sizeMetges() {
		return this.metgesAmbAccesProtegit.size();
	}

	/**
	 * Retorna el nombre de visites associades
	 * @return nombre d'elements
	 * @see java.util.Set#size()
	 */
	public int sizeVisites() {
		return this.visitesProtegides.size();
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
				.appendSuper(super.toString())
				.append("id", this.id)
				.append("visitesProtegides", this.visitesProtegides)
				.append("metgesAmbAccesProtegit", this.metgesAmbAccesProtegit)
				.toString();
	}



}
